package gen;

import gen.model.IDatatype;
import gen.model.ModelAttribute;
import gen.model.ModelClass;
import gen.model.ModelDatatype;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

public class LoadUtil {

	public static void loadTypes(Document doc, String packageName, String label, Map<String, IDatatype> dataTypes) {
		System.out.println("Loading Package: " + packageName);
		//
		Node XMIContent = XMLUtil.getChildNode(doc.getFirstChild(), "XMI.content");
		List<Node> packages_ = XMLUtil.getChildNodes(XMIContent, "Model:Package");
		for (Node node : packages_) {
			String name = XMLUtil.getAttributeValue(node, "name");
			if (name.equals(packageName)) {
				Node contents = XMLUtil.getChildNode(node, "Model:Namespace.contents");
				//
				List<Node> classes = XMLUtil.getChildNodes(contents, "Model:Class");
				for (Node clazz : classes) {
					loadModelClass(clazz, dataTypes, label);
				}
				//
				List<Node> datatypes = XMLUtil.getChildNodes(contents, "Model:DataType");
				for (Node datatype : datatypes) {
					loadModelDatatype(datatype, dataTypes, label);
				}
			}
		}
	}

	private static void loadModelDatatype(Node node, Map<String, IDatatype> objects, String label) {
		//
		String aux = XMLUtil.getAttributeValue(node, "name");
		String name = renameClassIfNeeded(aux);
		//
		System.out.println(" Datatype: " + aux + (aux.equals(name) ? "" : "->" + name));
		//
		String xmi_id = XMLUtil.getAttributeValue(node, "xmi.id");
		//
		ModelDatatype datatype = new ModelDatatype();
		objects.put(xmi_id, datatype);
		//
		datatype.setXmi_id(xmi_id);
		datatype.setName(name);
		datatype.label = label;
	}

	private static void loadModelClass(Node node, Map<String, IDatatype> objects, String label) {
		//
		String aux = XMLUtil.getAttributeValue(node, "name");
		String name = renameClassIfNeeded(aux);
		//
		System.out.println(" Class: " + aux + (aux.equals(name) ? "" : "->" + name));
		//
		String xmi_id = XMLUtil.getAttributeValue(node, "xmi.id");
		//
		ModelClass modelClass = new ModelClass();
		objects.put(xmi_id, modelClass);
		//
		modelClass.setXmi_id(xmi_id);
		modelClass.setName(name);
		modelClass.setLabel(label);
		//
		String supertypes = XMLUtil.getAttributeValue(node, "supertypes");
		List<String> supertypesList = new ArrayList<String>();
		if (supertypes != null) {
			StringTokenizer st = new StringTokenizer(supertypes, " ");
			while (st.hasMoreTokens()) {
				String id = st.nextToken();
				supertypesList.add(id);
			}
		}
		modelClass.supertypes = supertypesList;
		//
		List<ModelAttribute> attributes = new ArrayList<ModelAttribute>();
		Node contents = XMLUtil.getChildNode(node, "Model:Namespace.contents");
		if (contents != null) {
			List<Node> atts = XMLUtil.getChildNodes(contents, "Model:Attribute");
			for (Node att : atts) {
				attributes.add(loadModelAttribute(att));
			}
			atts = XMLUtil.getChildNodes(contents, "Model:Reference");
			for (Node att : atts) {
				attributes.add(loadModelAttribute(att));
			}
		}
		modelClass.attributes = attributes;
	}

	private static String renameClassIfNeeded(String name) {
		if (name.equals("AggregationKind") || //
				name.equals("CallConcurrencyKind") || //
				name.equals("ChangeableKind") || //
				name.equals("Geometry") || //
				name.equals("LocationReference") || //
				name.equals("Name") || //
				name.equals("OrderingKind") || //
				name.equals("ParameterDirectionKind") || //
				name.equals("PseudostateKind") || //
				name.equals("ScopeKind") || //
				name.equals("UnlimitedInteger") || //
				name.equals("VisibilityKind") //
		) {
			return "String";
		}
		return name;
	}

	private static ModelAttribute loadModelAttribute(Node node) {
		//
		String name = XMLUtil.getAttributeValue(node, "name");
		//
		System.out.println("  Attribute: " + name);
		//
		String xmi_id = XMLUtil.getAttributeValue(node, "xmi.id");
		//
		ModelAttribute modelAttribute = new ModelAttribute();
		//
		modelAttribute.xmi_id = xmi_id;
		modelAttribute.name = name;
		//
		String type = XMLUtil.getAttributeValue(node, "type");
		modelAttribute.type = type;
		//
		boolean many = false;
		boolean optional = false;
		Node multiplicity = XMLUtil.getChildNode(node, "Model:StructuralFeature.multiplicity");
		if (multiplicity != null) {
			List<Node> fields = XMLUtil.getChildNodes(multiplicity, "XMI.field");
			//
			String aux = fields.get(0).getTextContent();
			optional = aux.equals("0");
			//
			aux = fields.get(1).getTextContent();
			many = !aux.equals("1");
		}
		modelAttribute.optional = optional;
		modelAttribute.many = many;
		//
		return modelAttribute;
	}

}
